package com.founder.chd_daily_query.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.founder.chd_daily_query.ChdDailyQueryApplication;
import com.founder.chd_daily_query.service.QueryService;
import com.founder.chd_daily_query.util.JsonUtil;
import javassist.expr.Instanceof;
import org.springframework.data.domain.Example;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class QueryServiceImpl implements QueryService {

    @Autowired
    ApplicationContext applicationContext;
    @Autowired
    private RedisTemplate <String,String> redisTemplate;


    RedisTemplate template;
    @Override
    public Object ReflectionQuery(String model,int startFrom, int num,String startTime,String endTime) throws ClassNotFoundException, ParseException {
        //反射生成对应的repo类型.Class
        Class<?> aClass = Class.forName("com.founder.chd_daily_query.repo.query." + model + "Repo");
        //IOC容器拿出对应的实例
        Object bean = applicationContext.getBean(aClass);
        PageRequest of = PageRequest.of(startFrom, num,Sort.by(Sort.Direction.DESC,"lastUpdateDate"));
        if(null != startTime && null != endTime){
            return ReflectionQueryByTime(bean,of,startTime,endTime);
        }else{
            JpaRepository repo =(JpaRepository)bean;
            long count = repo.count();

            Page all =  repo.findAll(of);
            List content = all.getContent();

            Map<String,Object> data =new HashMap<String,Object>();
            data.put("data",content);
            Map<String,Long> map=new HashMap<String, Long>();
            map.put("count",count);
            List<Object> res =new ArrayList<Object>(Arrays.asList(new Object[]{data, count}));
            //res.add(map);
            return res;
        }
    }

    public Object ReflectionQueryByTime(Object bean, PageRequest of, String startTime, String endTime){
        JpaSpecificationExecutor repoa = (JpaSpecificationExecutor) bean;
        Specification  specification = new Specification() {
            @Override
            public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {

                Date start = null;
                Date end = null;
                try {
                    start = new SimpleDateFormat("yyyy-MM-dd").parse(startTime);
                    end = new SimpleDateFormat("yyyy-MM-dd").parse(endTime);
                } catch (ParseException e) {
                    e.printStackTrace();
                }

                Predicate predicate = criteriaBuilder.between(root.get("createDate"),start,end);
                return predicate;
            }
        };

        Page all = repoa.findAll(specification,of);
        long count = repoa.count(specification);
        List content = all.getContent();
        Map<String,Object> data =new HashMap<String,Object>();
        data.put("data",content);
        Map<String,Long> map=new HashMap<String, Long>();
        map.put("count",count);
        List<Object> res =new ArrayList<Object>(Arrays.asList(new Object[]{data, count}));
        return res;
    }

    @Override
    public Object RelationQuery(String model,String field,String keyNum) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
        List res = (List)RelationQueryByRedis(model,field,keyNum);
        if(res.size()==0){
            return RelationQueryByDb(model,field,keyNum);
        }
        return res;
    }

    private Object RelationQueryByRedis(String model,String field,String keyNum){
        List<JSONObject> res = new ArrayList<JSONObject>();
        redisTemplate.opsForList().range(model+":"+field+":"+keyNum,0,-1).forEach(str->{
            res.add(JsonUtil.parse(str));
        });
        return res;
    }

    private Object RelationQueryByDb(String model,String field,String keyNum) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        Class<?> repoType = Class.forName("com.founder.chd_daily_query.repo.query." + model + "Repo");
        Class<?> entity = Class.forName("com.founder.chd_daily_query.entity.query." + model + "Entity");
        Method method = entity.getMethod("set"+field,String.class);
        Object o = entity.newInstance();
        method.invoke(o,String.valueOf(keyNum));
        JpaRepository repo  = (JpaRepository)applicationContext.getBean(repoType);
        Example<Object> of = Example.of(o);
        List all = repo.findAll(of);
        //获取toString方法

        all.forEach(str->{

            redisTemplate.opsForList().leftPush(model+":"+field+":"+keyNum,JSONObject.toJSONString(str));

        });
        redisTemplate.expire(model+":"+field+":"+keyNum,600, TimeUnit.SECONDS);

        return all;
    }

}
